home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / MDICLIEN.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  9KB  |  387 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1991, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.9  $
  6. //
  7. // Implementation of class TMDIClient.  This defines the basic behavior
  8. // of all MDI client windows.
  9. //----------------------------------------------------------------------------
  10. #pragma hdrignore SECTION
  11. #include <owl/pch.h>
  12. #if !defined(OWL_MDI_H)
  13. # include <owl/mdi.h>
  14. #endif
  15.  
  16. //
  17. // Define to not work around here in the client, the 'creating MDI child
  18. // maximized corrupts the menu bar' bug
  19. //
  20. #if !defined(NO_MDIMAX_WORKAROUND)
  21. # define MDIMAX_WORKAROUND
  22. #endif
  23.  
  24. OWL_DIAGINFO;
  25.  
  26. #if !defined(SECTION) || SECTION == 1
  27.  
  28. DEFINE_RESPONSE_TABLE1(TMDIClient, TWindow)
  29.   EV_COMMAND(CM_CREATECHILD, CmCreateChild),
  30.   EV_COMMAND(CM_TILECHILDREN, CmTileChildren),
  31.   EV_COMMAND(CM_TILECHILDRENHORIZ, CmTileChildrenHoriz),
  32.   EV_COMMAND(CM_CASCADECHILDREN, CmCascadeChildren),
  33.   EV_COMMAND(CM_ARRANGEICONS, CmArrangeIcons),
  34.   EV_COMMAND(CM_CLOSECHILDREN, CmCloseChildren),
  35.   EV_COMMAND_ENABLE(CM_TILECHILDREN, CmChildActionEnable),
  36.   EV_COMMAND_ENABLE(CM_TILECHILDRENHORIZ, CmChildActionEnable),
  37.   EV_COMMAND_ENABLE(CM_CASCADECHILDREN, CmChildActionEnable),
  38.   EV_COMMAND_ENABLE(CM_ARRANGEICONS, CmChildActionEnable),
  39.   EV_COMMAND_ENABLE(CM_CLOSECHILDREN, CmChildActionEnable),
  40.   EV_WM_MDICREATE,
  41.   EV_WM_MDIDESTROY,
  42.   EV_WM_DROPFILES,
  43. END_RESPONSE_TABLE;
  44.  
  45. //
  46. // Constructor for a TMDIClient
  47. //
  48. // Allocates a CLIENTCREATESTRUCT on the heap and
  49. // ClientAttr to point to this space
  50. //
  51. TMDIClient::TMDIClient(TModule* module)
  52. {
  53.   // Initialize virtual base, in case the derived-most used default ctor
  54.   //
  55.   TWindow::Init(0, 0, module);
  56.  
  57.   Attr.Id = IDW_MDICLIENT;
  58.  
  59.   // Allow client area to grow scroll bars if necessary
  60.   //
  61.   Attr.Style |= MDIS_ALLCHILDSTYLES | WS_GROUP | WS_TABSTOP | WS_CLIPCHILDREN|
  62.                 WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL | WS_BORDER;
  63.  
  64.   if (TSystem::Has3dUI()) {
  65.     Attr.Style &= ~WS_BORDER;
  66.     Attr.ExStyle |= 0x200L;  //WS_EX_CLIENTEDGE;
  67.   }
  68.  
  69.   ClientAttr = new CLIENTCREATESTRUCT;
  70.   ClientAttr->hWindowMenu = 0;
  71.   ClientAttr->idFirstChild = IDW_FIRSTMDICHILD;
  72.  
  73.   Attr.Param = (LPSTR)ClientAttr;
  74.   SetFlag(wfStreamTop);
  75. }
  76.  
  77. //
  78. // Constructor for a TMDIClient which is being used in a DLL as an alias
  79. // for a non-OWL window. This ctor is generally not used by derived
  80. // classes
  81. //
  82. TMDIClient::TMDIClient(THandle handle, TModule* module)
  83. :
  84.   TWindow(handle, module)
  85. {
  86.   ClientAttr = 0;
  87.   SetFlag(wfStreamTop);
  88. }
  89.  
  90. //
  91. // Frees the memory associated with ClientAttr
  92. //
  93. TMDIClient::~TMDIClient()
  94. {
  95.   delete ClientAttr;
  96. }
  97.  
  98. //
  99. // Return the Window's defined class name for MDI clients
  100. //
  101. char far*
  102. TMDIClient::GetClassName()
  103. {
  104.   return "MDICLIENT";
  105. }
  106.  
  107. //
  108. // Use the Windows message to get the active mdi child, and then down cast
  109. // to our MDI child derived class before returning it.
  110. //
  111. TMDIChild*
  112. TMDIClient::GetActiveMDIChild()
  113. {
  114.   THandle hWnd = THandle(HandleMessage(WM_MDIGETACTIVE));
  115.  
  116.   return TYPESAFE_DOWNCAST(GetWindowPtr(hWnd), TMDIChild);
  117. }
  118.  
  119. //
  120. //
  121. //
  122. void
  123. TMDIClient::ArrangeIcons()
  124. {
  125.   HandleMessage(WM_MDIICONARRANGE);
  126. }
  127.  
  128. //
  129. //
  130. //
  131. void
  132. TMDIClient::CascadeChildren()
  133. {
  134.   HandleMessage(WM_MDICASCADE);
  135. }
  136.  
  137. //
  138. //
  139. //
  140. void
  141. TMDIClient::TileChildren(int tile)
  142. {
  143.   HandleMessage(WM_MDITILE, tile);
  144. }
  145.  
  146. //
  147. // Preprocess messages in order to translate MDI accelerator keys
  148. //
  149. bool
  150. TMDIClient::PreProcessMsg(MSG& msg)
  151. {
  152.   if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
  153.     return TranslateMDISysAccel(GetHandle(), &msg);
  154.  
  155.   else
  156.     return false;
  157. }
  158.  
  159. //
  160. // Performs actual THandle creation. Fills in child menu handle by querying the
  161. // frame for it.
  162. //
  163. bool
  164. TMDIClient::Create()
  165. {
  166.   TMDIFrame*  frame = TYPESAFE_DOWNCAST(Parent,TMDIFrame);
  167.  
  168.   CHECK(frame);
  169.  
  170.   ClientAttr->hWindowMenu = frame->FindChildMenu(frame->GetMenu());
  171.   return TWindow::Create();
  172. }
  173.  
  174. //
  175. // Creates a valid new MDI child window after calling InitChild() to construct
  176. // a new MDI child window object
  177. //
  178. TWindow*
  179. TMDIClient::CreateChild()
  180. {
  181.   TMDIChild* child = InitChild();
  182.   CHECK(child);
  183.   if (child->Create())
  184.     return child;
  185.   return 0;
  186. }
  187.  
  188. //
  189. // Can be overriden by derived classes to construct an instance of a
  190. // user-defined TMDIChild derived class as an MDI child window
  191. //
  192. TMDIChild*
  193. TMDIClient::InitChild()
  194. {
  195.   return new TMDIChild(*this);
  196. }
  197.  
  198. static bool
  199. sCannotClose(TWindow* win, void*)
  200. {
  201.   return !win->CanClose();
  202. }
  203.  
  204. static void
  205. sCloseChild(TWindow* win, void*)
  206. {
  207.   win->Destroy();
  208.   delete win;
  209. }
  210.  
  211. //
  212. // Closes each MDI child, after calling the child's CanClose() method to
  213. // ensure that it is Ok to do so
  214. //
  215. // Returns true if all children are closed(or there were no children),
  216. // false if any child can't be closed
  217. //
  218. bool
  219. TMDIClient::CloseChildren()
  220. {
  221.   if (!FirstThat(sCannotClose)) {
  222.     ForEach(sCloseChild);
  223.     return true;
  224.   }
  225.   return false;
  226. }
  227.  
  228. //
  229. // Handle WM_MDICREATE to perform actual creation of MDI children.
  230. //
  231. TResult
  232. TMDIClient::EvMDICreate(MDICREATESTRUCT far& createStruct)
  233. {
  234.   // Fill in default child window styles if they request style 0 since this
  235.   // client by default has set allchildstyles
  236.   //
  237.   if ((Attr.Style&MDIS_ALLCHILDSTYLES) && !createStruct.style)
  238.     createStruct.style =
  239.                WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
  240.                WS_SYSMENU | WS_CAPTION | WS_THICKFRAME |
  241.                WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
  242.  
  243.   // Work around a Windows MDI bug w/ bad menus if MDI child is created
  244.   // maximized, by hiding child now & maximizing later
  245.   //
  246. #if defined(MDIMAX_WORKAROUND)
  247.   uint32 origStyle = createStruct.style;
  248.   if (createStruct.style & WS_MAXIMIZE)
  249.     createStruct.style &= ~(WS_MAXIMIZE | WS_VISIBLE);
  250. #endif
  251.  
  252.   TResult result = DefaultProcessing();
  253.  
  254.   // Finish up maximized MDI child workaround
  255.   //
  256. #if defined(MDIMAX_WORKAROUND)
  257.   if (THandle(result) && (origStyle & WS_MAXIMIZE)) {
  258.     HandleMessage(WM_MDIMAXIMIZE, TParam1(result));
  259. #if defined(BI_PLAT_WIN32)
  260.     HandleMessage(WM_MDIREFRESHMENU);
  261. #else
  262.     HandleMessage(WM_MDISETMENU, true);
  263. #endif
  264.   }
  265. #endif
  266.  
  267.   return result;
  268. }
  269.  
  270. //
  271. // When an MDI child is destroyed while other children are hidden or disabled,
  272. // the Windows MDI child management gets confused causing subsequent failure.
  273. // To prevent this, we temporarily unhide and enable siblings during destroy.
  274. //
  275. static void sUnHide(TWindow* win, void* hWnd)
  276. {
  277.   if (*win == TWindow::THandle(hWnd) || !win->IsWindow())
  278.     return;
  279.   if (!win->IsWindowVisible()) {
  280.     win->SetWindowPos(0, 0, 0, 0, 0,
  281.                       SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE|
  282.                       SWP_NOZORDER|SWP_SHOWWINDOW);
  283.     win->SetFlag(wfUnHidden);
  284.   }
  285.   if (!win->IsWindowEnabled()) {
  286.     win->EnableWindow(true);
  287.     win->SetFlag(wfUnDisabled);
  288.   }
  289. }
  290.  
  291. //
  292. //
  293. //
  294. static void sReHide(TWindow* win, void*)
  295. {
  296.   if (!*win)
  297.     return;
  298.   if (win->IsFlagSet(wfUnHidden)) {
  299.     win->ClearFlag(wfUnHidden);
  300.     win->ShowWindow(SW_HIDE);
  301.   }
  302.   if (win->IsFlagSet(wfUnDisabled)) {
  303.     win->ClearFlag(wfUnDisabled);
  304.     win->EnableWindow(false);
  305.   }
  306. }
  307.  
  308. //
  309. // Destroy an MDI child window. Must temporarily unhide any hidden children,
  310. // and then rehide them after the destruction. Otherwise Window's MDI client
  311. // gets confused
  312. //
  313. void
  314. TMDIClient::EvMDIDestroy(THandle THandle)
  315. {
  316.   ForEach(sUnHide, (void*)THandle);
  317.   DefaultProcessing();
  318.   ForEach(sReHide);
  319. #if defined(BI_PLAT_WIN32)
  320.   HandleMessage(WM_MDIREFRESHMENU);
  321. #else
  322.   HandleMessage(WM_MDISETMENU, true);
  323. #endif
  324. }
  325.  
  326. //
  327. // Forward dropped file messages by default to the parent (MDI Frame) where
  328. // they can be handled, or allowed to forward to the app where they can be
  329. // handled easier.
  330. //
  331. void
  332. TMDIClient::EvDropFiles(TDropInfo)
  333. {
  334.   Parent->ForwardMessage();
  335. }
  336.  
  337. //
  338. // Enables any of the child action menu items if any MDI children exit
  339. //
  340. void
  341. TMDIClient::CmChildActionEnable(TCommandEnabler& commandEnabler)
  342. {
  343.   commandEnabler.Enable(GetFirstChild() != 0);
  344. }
  345.  
  346.  
  347. #endif
  348. #if !defined(SECTION) || SECTION == 2
  349.  
  350. IMPLEMENT_STREAMABLE1(TMDIClient, TWindow);
  351.  
  352. #if !defined(BI_NO_OBJ_STREAMING)
  353.  
  354. //
  355. // Reads an instance of TMDIClient from the passed ipstream
  356. //
  357. void*
  358. TMDIClient::Streamer::Read(ipstream& is, uint32 /*version*/) const
  359. {
  360.   ReadBaseObject((TWindow*)GetObject(), is);
  361.  
  362.   if (GetObject()->ClientAttr == 0)
  363.     GetObject()->ClientAttr = new CLIENTCREATESTRUCT;  //far
  364.  
  365.   uint idFirstChild;  // Need temp for near data model since ClientAttr is far
  366.   is >> idFirstChild;
  367.   GetObject()->ClientAttr->idFirstChild = idFirstChild;
  368.   GetObject()->ClientAttr->hWindowMenu = (HMENU) 0;
  369.   GetObject()->Attr.Param = (LPSTR)GetObject()->ClientAttr;
  370.  
  371.   return GetObject();
  372. }
  373.  
  374. //
  375. // Writes the TMDIClient to the passed opstream
  376. //
  377. void
  378. TMDIClient::Streamer::Write(opstream& os) const
  379. {
  380.   WriteBaseObject((TWindow*)GetObject(), os);
  381.   os << GetObject()->ClientAttr->idFirstChild;
  382. }
  383.  
  384. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  385.  
  386. #endif
  387.